/*
  tester.c - Test implementation of pgfltstats system call.
  Ben Marks, Chris Lekas

  Runs pgfltstats and prints the result. Also, checks a number of error
  conditions.
 */


#include <stdio.h>
#include <unistd.h>
#include <linux/pgfltstats.h>

#define pgfltstats(x, y, z)         syscall( 304, x, y, z )

// Function declarations
void errorChecks();

/*
  errorChecks() : Test pgfltstats against the following error conditions:
  => Bad flag value
  => NULL pointer value
  => Bogus pointer value
  => Pid < -1
  => Nonexistant pid

  Parameters: None. 
  Returns: Nothing.

 */
void errorChecks() {

  struct pf_info_struct s;
  printf("Testing passing a bad flag value\n");
  if ( pgfltstats( 1, 1234, &s ) ) {
    perror("Bad Flag: ");
  }

  printf("Testing passing in a NULL pointer\n");
  if ( pgfltstats( 0, PGFLTSTAT_PROC, NULL ) ) {
    perror("NULL Pointer: ");
  }

  printf("Testing passing in a bogus pointer\n");
  if ( pgfltstats( 0, PGFLTSTAT_OWNER, 0xffffffffffffffffffff ) ) {
    perror("Bogus Pointer: ");
  }


  printf("Testing a PID that (probably) doesn't exist\n");
  if ( pgfltstats( 15002, PGFLTSTAT_PROC, &s ) ) {
    perror("Bad PID: ");
  }

  printf("Testing a PID that is negative and not -1\n");
  if ( pgfltstats( -50, PGFLTSTAT_PROC, &s ) ) {
    perror("Negative PID: ");
  }

}

/*
  main: Runs pgfltstats and prints the result. Also, checks different
  error conditions.

  Takes in 2 command line arguments: 
  argv[1] should be a PID to use in the pgfltstats system call
  argv[2] should be nonzero if PGFLTSTAT_PROC should be used in
          pgfltstats, and zero if PGFLTSTAT_OWNER should be used.
	  It is not referenced if pid = -1.

  Returns 0 on success, -1 on failure.
 */
int main(int argc, char ** argv) {

    
  struct pf_info_struct s;
 
  // Check usage
  if ( argc < 3 ) {
    printf("Usage: %s <PID value> <Use PROC flag>\n", argv[0]);
    return -1;
  }

  // Convert arguments to appropriate values for pgfltstats call
  int pid = atoi(argv[1]);
  int flag = ( (atoi(argv[2])) ? PGFLTSTAT_PROC : PGFLTSTAT_OWNER );

  // Tell the user what we're doing
  if ( pid == -1 ) {
    printf("Finding information about all system processes\n");
  }
  else {
    if ( flag == PGFLTSTAT_PROC ) {
      printf("Finding page fault information for process: %d\n", pid);
    }
    else {
      printf("Finding page fault information for owner of PID %d\n", pid);
    }
  }

  // Call pgfltstats with their values
  if ( pgfltstats( pid, flag, &s ) ) {
    perror("pgfltstats");
    return -1;
  }

  // Print out the results
  printf("\t  Major Page Faults: %lu\n", s.major);
  printf("\t  Minor Page Faults: %lu\n", s.minor);
  printf("\nNumber of Processes: %d\n", s.num_procs);

  // Check different error conditions.
  printf("Checking against different error conditions\n");
  errorChecks();

  return 0; 

  

}
